﻿/******************************************************
* author :  cwj
* email  :  chenwenji_360@live.com 
* history:  created by cwj 2015/7/16 16:07:29 
* clrversion :4.0.30319.18444
******************************************************/

using Machine.DataAccess.Common;
using Machine.DataAccess.Common.ORM;
using Machine.DataAccess.Linq;
using Machine.DataAccess.Operation;
using Machine.DataAccess.Operation.Access;
using Machine.DataAccess.Operation.Mysql;
using Machine.DataAccess.Operation.Sqlite;
using Machine.DataAccess.Operation.SqlServer;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Configuration;
using System.Data.Common;
using System.Linq;
using System.Text;

namespace Machine.DataAccess
{
    class Config : ConfigurationSection
    {
        private static Lazy<Config> _instance = new Lazy<Config>(() =>
        {
            return ConfigurationManager.GetSection("DataAccess") as Config;
        }, true);
        public static Config Instance { get { return _instance.Value; } }
        private Config() {  }

        //private DbProviderFactory providerFactory;
        //internal DbProviderFactory ProviderFactory
        //{
        //    get
        //    {
        //        if (providerFactory == null)
        //        {
        //            providerFactory = DbProviderFactories.GetFactory(this.DefaultProvider.Provider);
        //        }
        //        return providerFactory;
        //    }
        //}

        //private const string DEFAULT_PROVIDER = "default";
        //[ConfigurationProperty(DEFAULT_PROVIDER, IsRequired = true)]
        public string DefaultProviderName
        {
            get { return this.ConnectionCollections.Default.ToLower(); }
        }

        private const string CONNECTION_COLLECTIONNAME = "providers";
        [ConfigurationProperty(CONNECTION_COLLECTIONNAME, IsDefaultCollection = true, IsRequired = true)]
        public ProviderElementCollection ConnectionCollections
        {
            get { return (ProviderElementCollection)base[CONNECTION_COLLECTIONNAME]; }
        }

        private ConcurrentDictionary<string, ProviderElement> defaultProviderCache = new ConcurrentDictionary<string,ProviderElement>();
        [Obsolete]
        public ProviderElement DefaultProvider
        {
            get
            {
                //if (defaultProviderCache == null) this.defaultProviderCache = this.ConnectionCollections.Cast<ProviderElement>().ToDictionary(x => x.Key.ToLower());
                //if (this.defaultProviderCache.ContainsKey(DefaultProviderName)) return defaultProviderCache[this.DefaultProviderName];
                throw new ArgumentNullException("找不到默认的连接信息");
            }
        }
        public bool AddProvider(string providerName, string connectionString,string provider ,bool isCodeFirst = false)
        {
            if (defaultProviderCache.ContainsKey(providerName)) return false;
            ProviderElement element = new ProviderElement();
            element.Key = providerName;
            element.ConnectionString = connectionString;
            element.Provider = provider;
            element.IsCodeFirst = isCodeFirst;
            defaultProviderCache[providerName] = element;
            return true;
        }

        public ProviderElement GetProviderByKey(string key = null)
        {
            if (defaultProviderCache.Count == 0)
            {
                foreach (var item in this.ConnectionCollections.Cast<ProviderElement>().ToDictionary(x => x.Key.ToLower()))
                {
                    if (!this.defaultProviderCache.ContainsKey(item.Key))
                    {
                        this.defaultProviderCache[item.Key] = item.Value;
                        //this.defaultProviderCache.AddOrUpdate(item.Key, item.Value, (ckey, element) => { return element; });
                    }
                }
                //this.defaultProviderCache = new ConcurrentDictionary<string, ProviderElement>();
            }
            key = key ?? this.DefaultProviderName;
            if (key != null) key = key.ToLower();
            if (defaultProviderCache.ContainsKey(key)) return defaultProviderCache[key];

            if (!string.IsNullOrEmpty(Config.Instance.Manager.Provider))
            {
                if (key == null || key == string.Empty) throw new ArgumentException("自动创建数据库参数不支持空");
                var providerElement = new DatabaseCreator().CreateDatabase(key);
                this.defaultProviderCache[key] = providerElement;
                return providerElement;
            }
            else
            {
                return null;
            }
            //throw new ArgumentNullException("找不到连接信息");
        }

        internal SetFormatBase GetFormatVistor(ProviderElement providerElement)
        {
            switch (providerElement.Provider)
            {
                case "System.Data.SqlClient":
                    return new SQLServerFormat(providerElement);
                case "System.Data.SQLite":
                    return new SqliteFormat(providerElement);
                case "MySql.Data.MySqlClient":
                    return new MySqlFormat(providerElement);
                case "System.Data.OleDb":
                    return new AccessFormat(providerElement);
                default:
                    throw new NotSupportedException(string.Format("暂时不支持这种类型:{0}", this.DefaultProvider.Provider));
            }
        }

        internal IDataSetOperator<TEntity> GetDataSetOperator<TEntity>(ProviderElement providerElement)
        {
            switch (providerElement.Provider)
            {
                case "System.Data.SqlClient":
                    return new SqlServerDataSetOperator<TEntity>(providerElement);
                case "System.Data.SQLite":
                    return new SqliteDbSetOperation<TEntity>(providerElement);
                case "MySql.Data.MySqlClient":
                    return new MysqlDbSetOperation<TEntity>(providerElement);
                case "System.Data.OleDb":
                    return new AccessDbSetOperation<TEntity>(providerElement);
                default:
                    throw new NotSupportedException(string.Format("暂时不支持这种类型的操作:{0}", this.DefaultProvider.Provider));
            }
        }

        internal DbSchemInfoBase GetDbSchemInfo(ProviderElement providerElement)
        {
            switch (providerElement.Provider)
            {
                case "System.Data.SqlClient":
                    return new SqlServerSchemInfo(providerElement);//new NotSupportedException("暂时不支持");
                case "System.Data.SQLite":
                    return new SqliteSchemInfo(providerElement);
                case "MySql.Data.MySqlClient":
                    return new MySqlSchemInfo(providerElement);
                case "System.Data.OleDb":
                    return new AccessSchemInfo(providerElement);
                default:
                    throw new NotSupportedException(string.Format("暂时不支持这种类型的操作:{0}", this.DefaultProvider.Provider));
            }
        }

        internal DataSchemCreatorBase GetDbSchemCreator(ProviderElement providerElement)
        {
            switch (providerElement.Provider)
            {
                case "System.Data.SqlClient":
                    return new SqlServerDataSchemCreator(providerElement);
                case "System.Data.SQLite":
                    return providerElement.IsCodeFirst ? new SqliteDataSchemCreator(providerElement) : null;
                case "MySql.Data.MySqlClient":
                    return providerElement.IsCodeFirst ? new MysqlDataSchemCreator(providerElement) : null;
                case "System.Data.OleDb":
                    return providerElement.IsCodeFirst ? new AccessDataSchemCreator(providerElement) : null;
                default:
                    throw new NotSupportedException(string.Format("暂时不支持这种类型的操作:{0}", this.DefaultProvider.Provider));
            }
        }

        private const string DATABASE_MANAGE_NAME = "DatabaseManager";
        [ConfigurationProperty(DATABASE_MANAGE_NAME)]
        public DatabaseManager Manager
        {
            get { return (DatabaseManager)base[DATABASE_MANAGE_NAME]; }
            set { base[DATABASE_MANAGE_NAME] = value; }
        }
    }

    public class ProviderElement : ConfigurationElement
    {
        private const string CONNECTION_KEYNAME = "name";
        [ConfigurationProperty(CONNECTION_KEYNAME, IsRequired = true, IsKey = true)]
        public string Key
        {
            get { return (string)base[CONNECTION_KEYNAME]; }
            set { base[CONNECTION_KEYNAME] = value; }
        }

        private const string CONNECTION_STRING_NAME = "connectionString";
        [ConfigurationProperty(CONNECTION_STRING_NAME, IsRequired = true)]
        public string ConnectionString
        {
            get { return (string)base[CONNECTION_STRING_NAME]; }
            set { base[CONNECTION_STRING_NAME] = value; }
        }

        private const string PROVIDER_STRING_NAME = "provider";
        [ConfigurationProperty(PROVIDER_STRING_NAME, IsRequired = true)]
        public string Provider
        {
            get { return (string)base[PROVIDER_STRING_NAME]; }
            set { base[PROVIDER_STRING_NAME] = value; }
        }

        private const string CODEFIRST_BOOL_NAME = "isCodeFirst";
        [ConfigurationProperty(CODEFIRST_BOOL_NAME, IsRequired = false)]
        public bool IsCodeFirst
        {
            get { return (bool)base[CODEFIRST_BOOL_NAME]; }
            set { base[CODEFIRST_BOOL_NAME] = value; }
        }
    }

    class ProviderElementCollection : ConfigurationElementCollection
    {
        private const string DEFAULT_PROVIDER = "default";
        [ConfigurationProperty(DEFAULT_PROVIDER)]
        public string Default { get { return (string)base[DEFAULT_PROVIDER]; } }

        protected override ConfigurationElement CreateNewElement()
        {
            return new ProviderElement();
        }

        protected override object GetElementKey(ConfigurationElement element)
        {
            return (element as ProviderElement).Key;
        }
    }

    class DatabaseManager : ConfigurationElement
    {
        private const string PROVIDER_NAME = "Provider";
        [ConfigurationProperty(PROVIDER_NAME,IsRequired = true)]
        public string Provider
        {
            get { return (string)base[PROVIDER_NAME]; }
            set { base[PROVIDER_NAME] = value; }
        }

        private const string USER_NAME = "UserName";
        [ConfigurationProperty(USER_NAME,IsRequired = true)]
        public string UserName
        {
            get { return (string)base[USER_NAME]; }
            set { base[USER_NAME] = value; }
        }

        private const string PASSWORK = "Passwork";
        [ConfigurationProperty(PASSWORK)]
        public string PassWork
        {
            get { return (string)base[PASSWORK]; }
            set { base[PASSWORK] = value; }
        }

        //private const string CONNEXTION_TEMPLETE = "ConnectionString";
        //[ConfigurationProperty(CONNEXTION_TEMPLETE, IsRequired = true)]
        //public string ConnectionString
        //{
        //    get { return (string)base[CONNEXTION_TEMPLETE]; }
        //    set { base[CONNEXTION_TEMPLETE] = value; }
        //}

        private const string PORT_TEMPLETE = "Port";
        [ConfigurationProperty(PORT_TEMPLETE, DefaultValue = "3306")]
        public string Port
        {
            get { return (string)base[PORT_TEMPLETE]; }
            set { base[PORT_TEMPLETE] = value; }
        }

        private const string ADDRESS_TEMPLETE = "Address";
        [ConfigurationProperty(ADDRESS_TEMPLETE, DefaultValue = "localhost")]
        public string Address
        {
            get { return (string)base[ADDRESS_TEMPLETE]; }
            set { base[ADDRESS_TEMPLETE] = value; }
        }
    }

}
